﻿#if MAPEDITOR
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Xml;
using System.ComponentModel;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Intermediate;
using FolderData;
using FarseerGames.SimpleSamplesXNA.DrawingSystem;
using System.Diagnostics;


namespace Folder
{
    public class MapEditor
    {
        #region Definitions

        public class MapEditorCloseEventArgs : EventArgs
        {
            public Map Map;
            public MapEditorCloseEventArgs(Map map)
            {
                this.Map = map;
            }
        }
        
        /// <summary>
        /// PosDesc에서 사용되는 EventArgument
        /// PosDesc의 Position이 변경되면 특정행동을 할 수 있게 하려고 이벤트-드리븐 방식을 사용했다.
        /// </summary>
        public class PosDescEventArgs : EventArgs
        {
            public Vector2 OldPos;
            public Vector2 NewPos;
            public PosDescEventArgs(Vector2 oldPos, Vector2 newPos)
            {
                OldPos = oldPos;
                NewPos = newPos;
            }
        }

        /// <summary>
        /// 위치와 그에 대한 설명을 담은 클래스.
        /// Start Position과 같은 맵의 특정 위치를 잡는데 사용된다.
        /// </summary>
        public class PosDesc
        {
            protected string _desc;
            protected Vector2 _pos;
            protected bool _isLocked;

            [ReadOnly(true)]
            public string Desc
            {
                get { return _desc; }
                set { _desc = value; }
            }

            public Vector2 Position
            {
                get { return _pos; }
                set
                {
                    Vector2 oldPos = _pos;
                    _pos = value;
                    PositionChanged(this, new PosDescEventArgs(oldPos, value));
                }
            }

            [DescriptionAttribute("true이면 물체가 마우스나 키보드의 입력에 움직이지 않습니다.")]
            public bool IsLocked
            {
                get { return _isLocked; }
                set { _isLocked = value; }
            }

            public event EventHandler<PosDescEventArgs> PositionChanged;

            public PosDesc(string Desc, Vector2 pos)
            {
                _desc = Desc;
                _pos = pos;
                _isLocked = false;
            }
        }

        /// <summary>
        /// MapEditor에서 마우스나 키보드로 선택된 물체를 관리하기 쉽도록 만듬.
        /// 선택된 물체의 래퍼
        /// </summary>
        public class SelectedObject
        {
            public enum SelectedKind
            {
                None,
                Substance,
                PosDesc,
            }

            private object selected;
            private SelectedKind kind;
            public object Selected
            {
                get { return selected; }
                set
                {
                    selected = value;
                    if (value == null)
                        kind = SelectedKind.None;
                    else if (value.GetType().IsSubclassOf(typeof(Substance)))
                    {
                        kind = SelectedKind.Substance;
                    }
                    else if (value.GetType() == typeof(PosDesc))
                    {
                        kind = SelectedKind.PosDesc;
                    }
                    else
                        throw new ArgumentException("알 수 없는 타입의 물체가 선택됨.");
                }
            }
            public SelectedKind Kind
            {
                get { return kind; }
            }

            public SelectedObject()
            {
                selected = null;
                kind = SelectedKind.None;
            }
        }
        #endregion

        #region Control and Components
        Form mainForm;
        MapProperty mapPropertyForm;
        VScrollBar vScrollBar;
        HScrollBar hScrollBar;
        MenuStrip menuStrip1;
        ToolStripMenuItem fileToolStripMenuItem;
        ToolStripMenuItem optionsToolStripMenuItem;
        ToolStripMenuItem windowToolStripMenuItem;
        ToolStripMenuItem newToolStripMenuItem;
        ToolStripMenuItem saveToolStripMenuItem;
        ToolStripMenuItem saveAsToolStripMenuItem;
        ToolStripMenuItem loadToolStripMenuItem;
        ToolStripMenuItem changeResolutionToolStripMenuItem;
        ToolStripMenuItem backToTheGameToolStripMenuItem;
        ToolStripMenuItem mapInfoStripMenuItem;
        InputDialog mapNameDialog;
        MapInfo mapInfoDialog;

        #endregion

        #region Fields And Initialize Methods

        static readonly int ScrollOffset = 500;     //맵의 가장자리에서 추가로 스크롤할 부분 (단위 pixel)
        bool isMapEditing;
        Map toEditMap;
        string oldTitle;
        string mapFileName;
        Vector2? oldCameraPos;
        Point lastDragPoint;        //마우스 오른쪽 버튼 드래그 시작할 때의 마우스 좌표
        Point lastScrollPoint;      //마우스 오른쪽 버튼 드래그 시작할 때의 스크롤바 값
        bool isDragging;
        bool isMapInfoDialoging;    //MapInfoDialog를 보여주고 있는가? 보여주고 있으면 배치 관련 키보드 인풋을 받지 않음.
        MouseButtons lastButton;
        KeyboardState oldKeyState;
        Dictionary<Substance, Substance.DataSet> dataTable;
        LineBrush selectedBrush, boundaryBrush;
        Texture2D startPosTexture;
        Texture2D startSelectedTexture;
        Texture2D noMontserTexture;
        Texture2D noMonsterSelectedTexture;
        PosDesc startCharPosDesc;
        SelectedObject selectedObject;
        List<PosDesc> monsterBlockDescs;
        ScreenManager screenManager;
        GraphicsDeviceManager graphics;
        ContentManager content;

        public Map ToEditMap
        {
            //변경은 StartMapEditor()함수를 통해서만 가능
            get { return toEditMap; }
        }
        public bool IsMapEditing
        {
            //변경은 StartMapEditor(), CloseMapEditor()함수를 통해서만 가능.
            get { return isMapEditing; }
        }
        public ScreenManager ScreenManager
        {
            get { return screenManager; }
            set { screenManager = value; }
        }
        public GraphicsDeviceManager Graphics
        {
            get { return graphics; }
            set { graphics = value; }
        }

        //Events
        public event EventHandler<MapEditorCloseEventArgs> MapEditorClosed;

        private void initializeMenuStrip()
        {
            //construct
            menuStrip1 = new MenuStrip();
            fileToolStripMenuItem = new ToolStripMenuItem();
            optionsToolStripMenuItem = new ToolStripMenuItem();
            windowToolStripMenuItem = new ToolStripMenuItem();
            newToolStripMenuItem = new ToolStripMenuItem();
            saveToolStripMenuItem = new ToolStripMenuItem();
            saveAsToolStripMenuItem = new ToolStripMenuItem();
            loadToolStripMenuItem = new ToolStripMenuItem();
            changeResolutionToolStripMenuItem = new ToolStripMenuItem();
            backToTheGameToolStripMenuItem = new ToolStripMenuItem();
            mapInfoStripMenuItem = new ToolStripMenuItem();
            menuStrip1.SuspendLayout();

            // menuStrip1
            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] 
            {
                this.fileToolStripMenuItem,
                this.optionsToolStripMenuItem,
                this.windowToolStripMenuItem,
                this.backToTheGameToolStripMenuItem,
                this.mapInfoStripMenuItem
            });
            this.menuStrip1.Location = new System.Drawing.Point(0, 0);
            this.menuStrip1.Name = "menuStrip1";
            this.menuStrip1.Size = new System.Drawing.Size(655, 24);
            this.menuStrip1.TabIndex = 7;
            this.menuStrip1.Text = "menuStrip1";

            // fileToolStripMenuItem
            this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.newToolStripMenuItem,
            this.saveToolStripMenuItem,
            this.saveAsToolStripMenuItem,
            this.loadToolStripMenuItem,});
            this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
            this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
            this.fileToolStripMenuItem.Text = "File";

            // optionsToolStripMenuItem
            this.optionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.changeResolutionToolStripMenuItem});
            this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem";
            this.optionsToolStripMenuItem.Size = new System.Drawing.Size(60, 20);
            this.optionsToolStripMenuItem.Text = "Options";

            // windowToolStripMenuItem
            this.windowToolStripMenuItem.Name = "windowToolStripMenuItem";
            this.windowToolStripMenuItem.Size = new System.Drawing.Size(61, 20);
            this.windowToolStripMenuItem.Text = "Window";

            // newToolStripMenuItem
            this.newToolStripMenuItem.Name = "newToolStripMenuItem";
            this.newToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.newToolStripMenuItem.Text = "New";

            // saveToolStripMenuItem
            this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
            this.saveToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.saveToolStripMenuItem.Text = "Save";

            //saveAsToolStripMenuItem
            this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
            this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.saveAsToolStripMenuItem.Text = "Save As";

            // loadToolStripMenuItem
            this.loadToolStripMenuItem.Name = "loadToolStripMenuItem";
            this.loadToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.loadToolStripMenuItem.Text = "Load";

            // changeResolutionToolStripMenuItem
            this.changeResolutionToolStripMenuItem.Name = "changeResolutionToolStripMenuItem";
            this.changeResolutionToolStripMenuItem.Size = new System.Drawing.Size(183, 22);
            this.changeResolutionToolStripMenuItem.Text = "Change Resolution";

            // backToTheGameToolStripMenuItem
            this.backToTheGameToolStripMenuItem.Name = "backToTheGameToolStripMenuItem";
            this.backToTheGameToolStripMenuItem.Size = new System.Drawing.Size(118, 20);
            this.backToTheGameToolStripMenuItem.Text = "Back to the Game";
            this.backToTheGameToolStripMenuItem.ToolTipText = "File로 저장되지는 않습니다. 변경 사항을 저장하고 싶으면 꼭 다시 에디터로 돌아와 저장을 해야 합니다.";

            // mapInfoStripMenuItem
            this.mapInfoStripMenuItem.Name = "mapInfoStripMenuItem";
            this.mapInfoStripMenuItem.Size = new System.Drawing.Size(118, 20);
            this.mapInfoStripMenuItem.Text = "View Map Info";

            this.menuStrip1.ResumeLayout(false);
            this.menuStrip1.PerformLayout();
        }

        public void Initialize()
        {
            mainForm = Control.FromHandle(screenManager.Game.Window.Handle) as Form;
            isMapEditing = false;
            toEditMap = null;
            mapFileName = string.Empty;
            oldCameraPos = null;
            lastDragPoint = Point.Zero;
            lastScrollPoint = Point.Zero;
            isDragging = false;
            isMapInfoDialoging = false;
            oldKeyState = Keyboard.GetState();
            dataTable = new Dictionary<Substance, Substance.DataSet>();

            startCharPosDesc = new PosDesc("dummy", Vector2.Zero);
            monsterBlockDescs = new List<PosDesc>();

            //MapPropertyForm
            mapPropertyForm = new MapProperty();

            //vScrollBar
            vScrollBar = new VScrollBar();
            vScrollBar.Name = "vScrollBar";
            vScrollBar.Size = new System.Drawing.Size(20, Camera.SCREEN_HEIGHT - 20);
            vScrollBar.Location = new System.Drawing.Point(Camera.SCREEN_WIDTH - 20, 0);
            vScrollBar.Visible = false;
            vScrollBar.LargeChange = 100;

            //hScrollBar
            hScrollBar = new HScrollBar();
            hScrollBar.Name = "hScrollBar";
            hScrollBar.Size = new System.Drawing.Size(Camera.SCREEN_WIDTH - 20, 20);
            hScrollBar.Location = new System.Drawing.Point(0, Camera.SCREEN_HEIGHT - 20);
            hScrollBar.Visible = false;
            hScrollBar.LargeChange = 100;

            //menustrip
            initializeMenuStrip();
            menuStrip1.Visible = false;

            //add
            mainForm.Controls.Add(vScrollBar);
            mainForm.Controls.Add(hScrollBar);
            mainForm.Controls.Add(menuStrip1);

            //layout
            mainForm.ResumeLayout(false);
            mainForm.PerformLayout();

            //mapNameDialog
            mapNameDialog = new InputDialog();
            mapNameDialog.SetDialog("Folder Map Editor", "맵 이름을 입력해 주세요.");

            //mapInfoDialog
            mapInfoDialog = new MapInfo();
        }

        public void LoadContent()
        {
            content = screenManager.Game.Content;
            startPosTexture = content.Load<Texture2D>("MapEditor/startPos");
            startSelectedTexture = content.Load<Texture2D>("MapEditor/selectedStart");
            noMontserTexture = content.Load<Texture2D>("MapEditor/noMonster");
            noMonsterSelectedTexture = content.Load<Texture2D>("MapEditor/noMonsterSelect");
            selectedBrush = new LineBrush(1, Color.Red);
            selectedBrush.Load(screenManager.GraphicsDevice);
            boundaryBrush = new LineBrush(2, Color.GreenYellow);
            boundaryBrush.Load(screenManager.GraphicsDevice);
        }

        #endregion

        #region General Methods

        /// <summary>
        /// 맵 에디터의 가지고 있는 스테이트를 초기화 합니다.
        /// 카메라, 스크롤, Substance, 몬스터 블록등을 다시 부릅니다.
        /// </summary>
        private void resetMapEditor()
        {
            //reset scrollbar 
            int minScrollX, maxScrollX, minScrollY, maxScrollY;
            minScrollX = 0;
            maxScrollX = 0;
            minScrollY = 0;
            maxScrollY = 0;

            //모든 substance가 scrool될 수 있도록 한다.
            foreach (var s in toEditMap.Substances.Values)
            {
                if (s.Position.X > maxScrollX)
                    maxScrollX = (int)s.Position.X;
                if (s.Position.X < minScrollX)
                    minScrollX = (int)s.Position.X;
                if (s.Position.Y > maxScrollY)
                    maxScrollY = (int)s.Position.Y;
                if (s.Position.Y < minScrollY)
                    minScrollY = (int)s.Position.Y;
            }

            //카메라가 scroll의 범위 안에 있게 한다.
            if (toEditMap.Camera.Position.X > maxScrollX)
                maxScrollX = (int)toEditMap.Camera.Position.X;
            if (toEditMap.Camera.Position.X < minScrollX)
                minScrollX = (int)toEditMap.Camera.Position.X;
            if (toEditMap.Camera.Position.Y > maxScrollY)
                maxScrollY = (int)toEditMap.Camera.Position.Y;
            if (toEditMap.Camera.Position.Y < minScrollY)
                minScrollY = (int)toEditMap.Camera.Position.Y;


            hScrollBar.Minimum = minScrollX - ScrollOffset;
            hScrollBar.Maximum = maxScrollX + ScrollOffset;
            vScrollBar.Minimum = minScrollY - ScrollOffset;
            vScrollBar.Maximum = maxScrollY + ScrollOffset;

            oldCameraPos = null;
            hScrollBar.Value = (int)toEditMap.Camera.Position.X;
            vScrollBar.Value = (int)toEditMap.Camera.Position.Y;
            //vScrollBar.LargeChange = (Math.Abs(vScrollBar.Maximum) / 10 + Math.Abs(vScrollBar.Minimum) / 10);
            //hScrollBar.LargeChange = (Math.Abs(hScrollBar.Maximum) / 10 + Math.Abs(hScrollBar.Minimum) / 10);

            mapPropertyForm.SetData(toEditMap);
            dataTable = ResourceManager.Instance.ReloadDatas(toEditMap);
            toEditMap.IsSaved = false;
            startCharPosDesc = new PosDesc("Character Starting Point", toEditMap.StartPos);
            startCharPosDesc.PositionChanged += new EventHandler<PosDescEventArgs>(startCharPosDesc_PositionChanged);
            selectedObject = new SelectedObject();
            selectedObject.Selected = null;

            monsterBlockDescs.Clear();
            foreach (Vector2 v in toEditMap.MonsterBlockPositions)
            {
                PosDesc pd = new PosDesc("Monster Block", v);
                pd.PositionChanged += new EventHandler<PosDescEventArgs>(pd_PositionChanged);
                monsterBlockDescs.Add(pd);
            }
        }

        private bool saveMapDialog()
        {
            SaveFileDialog saveDialog = new SaveFileDialog();
            saveDialog.Filter = "xml files (*.xml)|*.xml|All files(*.*)|*.*";
            saveDialog.FilterIndex = 0;
            if (saveDialog.ShowDialog() == DialogResult.OK)
            {
                mapFileName = saveDialog.FileName;
                saveMap();
                return true;
            }
            return false;
        }

        private void setFormTitle(string mapName)
        {
            mainForm.Text = string.Format("Folder - Map({0}) is being edited.", mapName);
        }

        private void saveMap()
        {
            try
            {
                //toEditMap을 mapFileName에 저장한다.
                XmlWriterSettings xmlSettings = new XmlWriterSettings();
                xmlSettings.Indent = true;

                using (XmlWriter xmlWriter = XmlWriter.Create(mapFileName, xmlSettings))
                {
                    IntermediateSerializer.Serialize(xmlWriter, toEditMap as object, null);
                }
                toEditMap.IsSaved = true;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
        }
        #endregion

        #region Update and Draw
        public void Update(GameTime gameTime)
        {
            KeyboardState state = Keyboard.GetState();
            if (isMapEditing && !isMapInfoDialoging && !mapPropertyForm.IsActivated)
            {
                #region Adding Substance
                if (state.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.A) && oldKeyState.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.A))
                {
                    if (!mapPropertyForm.SelectedName.Equals(string.Empty))
                    {
                        Substance s;
                        Substance.DataSet ds;
                        MouseState mst = Microsoft.Xna.Framework.Input.Mouse.GetState();
                        Vector2 pos = new Vector2(toEditMap.Camera.Position.X + (float)mst.X - Camera.SCREEN_WIDTH / 2f,
                            toEditMap.Camera.Position.Y + (float)mst.Y - Camera.SCREEN_HEIGHT / 2f);

                        switch (mapPropertyForm.SelectedKind)
                        {
                            case MapProperty.SubstanceKind.Character:
                                s = ResourceManager.Instance.GetResource<Character>(mapPropertyForm.SelectedName);
                                s.BindSimulator(toEditMap.Simulator);
                                s.Position = pos;
                                ds = (s as Character).GetDatas();
                                toEditMap.CharacterDatas.Add(ds as Character.CharacterDataSet);
                                break;
                            case MapProperty.SubstanceKind.Item:
                                s = ResourceManager.Instance.GetResource<Item>(mapPropertyForm.SelectedName);
                                s.BindSimulator(toEditMap.Simulator);
                                s.Position = pos;
                                ds = (s as Item).GetDatas();
                                toEditMap.ItemDatas.Add(ds as Item.ItemDataSet);
                                break;
                            case MapProperty.SubstanceKind.Terrain:
                                s = ResourceManager.Instance.GetResource<Terrain>(mapPropertyForm.SelectedName);
                                s.BindSimulator(toEditMap.Simulator);
                                s.Position = pos;
                                ds = (s as Terrain).GetDatas();
                                toEditMap.TerrainDatas.Add(ds as Terrain.TerrainDataSet);
                                break;
                            default:
                                throw new Exception("예상치 못한 종류의 SubstanceKind");
                        }
                        ds.Tag = s;
                        dataTable.Add(s, ds);

                        int postFixCount = 0;
                        while (!toEditMap.AddSubstance(s, ds.Name + "_" + postFixCount))
                            postFixCount++;
                        ds.id = ds.Name + "_" + postFixCount;

                        toEditMap.IsSaved = false;
                    }
                }
                #endregion

                #region Set Start Position
                if (state.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.S) && oldKeyState.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.S))
                {
                    MouseState st = Mouse.GetState();
                    startCharPosDesc.Position = new Vector2(toEditMap.Camera.Position.X + st.X - Camera.SCREEN_WIDTH / 2f,
                    toEditMap.Camera.Position.Y + st.Y - Camera.SCREEN_HEIGHT / 2f);
                    selectedObject.Selected = startCharPosDesc;
                    mapPropertyForm.Select(startCharPosDesc);
                    mapPropertyForm.RefreshGrid();
                }
                #endregion

                #region Add Monster Block
                if (state.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.W) && oldKeyState.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.W))
                {
                    MouseState st = Mouse.GetState();
                    PosDesc pd = new PosDesc("Monster Block", new Vector2(toEditMap.Camera.Position.X + st.X - Camera.SCREEN_WIDTH / 2f,
                        toEditMap.Camera.Position.Y + st.Y - Camera.SCREEN_HEIGHT / 2f));
                    pd.PositionChanged += new EventHandler<PosDescEventArgs>(pd_PositionChanged);
                    monsterBlockDescs.Add(pd);
                    toEditMap.MonsterBlockPositions.Add(pd.Position);
                    mapPropertyForm.Select(pd);
                    mapPropertyForm.RefreshGrid();
                }
                #endregion

                #region Moving the Selected Substance and PosDescs
                if (state.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Left) && oldKeyState.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.Left))
                {
                    if (selectedObject.Kind == SelectedObject.SelectedKind.Substance)
                    {
                        Substance selectedSubstance = selectedObject.Selected as Substance;
                        selectedSubstance.Position = new Vector2(selectedSubstance.Position.X - 1, selectedSubstance.Position.Y);
                        dataTable[selectedSubstance].Position = selectedSubstance.Position;
                        mapPropertyForm.RefreshGrid();
                    }
                    else if (selectedObject.Kind == SelectedObject.SelectedKind.PosDesc)
                    {
                        PosDesc pd = selectedObject.Selected as PosDesc;
                        pd.Position = new Vector2(pd.Position.X - 1, pd.Position.Y);
                    }
                    toEditMap.IsSaved = false;
                }
                if (state.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Right) && oldKeyState.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.Right))
                {
                    if (selectedObject.Kind == SelectedObject.SelectedKind.Substance)
                    {
                        Substance selectedSubstance = selectedObject.Selected as Substance;
                        selectedSubstance.Position = new Vector2(selectedSubstance.Position.X + 1, selectedSubstance.Position.Y);
                        dataTable[selectedSubstance].Position = selectedSubstance.Position;
                        mapPropertyForm.RefreshGrid();
                    }
                    else if (selectedObject.Kind == SelectedObject.SelectedKind.PosDesc)
                    {
                        PosDesc pd = selectedObject.Selected as PosDesc;
                        pd.Position = new Vector2(pd.Position.X + 1, pd.Position.Y);
                    }
                    toEditMap.IsSaved = false;
                }
                if (state.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Up) && oldKeyState.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.Up))
                {
                    if (selectedObject.Kind == SelectedObject.SelectedKind.Substance)
                    {
                        Substance selectedSubstance = selectedObject.Selected as Substance;
                        selectedSubstance.Position = new Vector2(selectedSubstance.Position.X, selectedSubstance.Position.Y - 1);
                        dataTable[selectedSubstance].Position = selectedSubstance.Position;
                        mapPropertyForm.RefreshGrid();
                    }
                    else if (selectedObject.Kind == SelectedObject.SelectedKind.PosDesc)
                    {
                        PosDesc pd = selectedObject.Selected as PosDesc;
                        pd.Position = new Vector2(pd.Position.X, pd.Position.Y - 1);
                    }
                    toEditMap.IsSaved = false;
                }
                if (state.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Down) && oldKeyState.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.Down))
                {
                    if (selectedObject.Kind == SelectedObject.SelectedKind.Substance)
                    {
                        Substance selectedSubstance = selectedObject.Selected as Substance;
                        selectedSubstance.Position = new Vector2(selectedSubstance.Position.X, selectedSubstance.Position.Y + 1);
                        dataTable[selectedSubstance].Position = selectedSubstance.Position;
                        mapPropertyForm.RefreshGrid();
                    }
                    else if (selectedObject.Kind == SelectedObject.SelectedKind.PosDesc)
                    {
                        PosDesc pd = selectedObject.Selected as PosDesc;
                        pd.Position = new Vector2(pd.Position.X - 1, pd.Position.Y + 1);
                    }
                    toEditMap.IsSaved = false;
                }

                #endregion

                #region Delete the selected substance or PosDesc.
                if (state.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.D) && oldKeyState.IsKeyUp(Microsoft.Xna.Framework.Input.Keys.D))
                {
                    if (selectedObject.Kind == SelectedObject.SelectedKind.Substance)
                    {
                        Substance selectedSubstance = selectedObject.Selected as Substance;
                        Substance.DataSet ds = dataTable[selectedSubstance];
                        Type t = selectedSubstance.GetType();
                        if (t == typeof(Character))
                            toEditMap.CharacterDatas.Remove(ds as Character.CharacterDataSet);
                        else if (t == typeof(Item))
                            toEditMap.ItemDatas.Remove(ds as Item.ItemDataSet);
                        else if (t == typeof(Terrain))
                            toEditMap.TerrainDatas.Remove(ds as Terrain.TerrainDataSet);
                        else
                            throw new Exception(string.Format("예상치 못한 타입. {0}", selectedSubstance.GetType()));

                        dataTable.Remove(selectedSubstance);
                        toEditMap.RemoveSubstance(selectedSubstance, ds.id);
                        selectedSubstance.UnbindSimulator();
                        selectedObject.Selected = null;
                        mapPropertyForm.Select(null);
                    }
                    else if (selectedObject.Kind == SelectedObject.SelectedKind.PosDesc)
                    {
                        if (selectedObject.Selected != startCharPosDesc)
                        {
                            PosDesc pd = selectedObject.Selected as PosDesc;
                            Debug.Assert(toEditMap.MonsterBlockPositions.IndexOf(pd.Position) >= 0);
                            toEditMap.MonsterBlockPositions.Remove(pd.Position);
                            monsterBlockDescs.Remove(pd);
                            selectedObject.Selected = null;
                            mapPropertyForm.Select(null);
                        }
                    }
                    toEditMap.IsSaved = false;
                }
                #endregion
            }

            oldKeyState = state;
        }

        /// <summary>
        /// 선택된 객체를 색칠합니다.
        /// spriteBatch가 begin되지 않은 상태여야 합니다. (자체적으로 begin합니다.)
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="color"></param>
        public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
        {
            RenderingHelper.DrawScene(toEditMap, FoldState.UNFOLDED, Vector3.Zero, Vector3.Zero, 0.0f, null, Color.White);

            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);

            toEditMap.DrawCharacters(spriteBatch, Color.White);

            //draw the start position of the map.
            spriteBatch.Draw(startPosTexture,
                new Vector2(toEditMap.StartPos.X + Camera.SCREEN_WIDTH / 2f - toEditMap.Camera.Position.X,
                toEditMap.StartPos.Y + Camera.SCREEN_HEIGHT / 2f - toEditMap.Camera.Position.Y), null, Color.White, 0f,
                new Vector2(startPosTexture.Width / 2f, startPosTexture.Height / 2f), 1f, SpriteEffects.None, 0f);

            //draw monster blocks
            foreach (Vector2 v in toEditMap.MonsterBlockPositions)
            {
                spriteBatch.Draw(noMontserTexture,
                    new Vector2(v.X + Camera.SCREEN_WIDTH / 2f - toEditMap.Camera.Position.X,
                        v.Y + Camera.SCREEN_HEIGHT / 2f - toEditMap.Camera.Position.Y),
                    null, Color.White, 0f,
                    new Vector2(noMontserTexture.Width / 2f, noMontserTexture.Height / 2f), 1f, SpriteEffects.None, 0f);
            }

            //draw selected object
            switch (selectedObject.Kind)
            {
                case SelectedObject.SelectedKind.None:
                    //do nothing
                    break;
                case SelectedObject.SelectedKind.PosDesc:
                    if (selectedObject.Selected == startCharPosDesc)
                    {
                        spriteBatch.Draw(startSelectedTexture,
                            new Vector2(toEditMap.StartPos.X + Camera.SCREEN_WIDTH / 2f - toEditMap.Camera.Position.X,
                            toEditMap.StartPos.Y + Camera.SCREEN_HEIGHT / 2f - toEditMap.Camera.Position.Y), null, Color.White, 0f,
                            new Vector2(startSelectedTexture.Width / 2f, startSelectedTexture.Height / 2f), 1f, SpriteEffects.None, 0f);
                    }
                    else //Monster Block Selected!
                    {
                        Vector2 pos = (selectedObject.Selected as PosDesc).Position;
                        spriteBatch.Draw(noMonsterSelectedTexture,
                            new Vector2(pos.X + Camera.SCREEN_WIDTH / 2f - toEditMap.Camera.Position.X,
                            pos.Y + Camera.SCREEN_HEIGHT / 2f - toEditMap.Camera.Position.Y), null, Color.White, 0f,
                            new Vector2(noMonsterSelectedTexture.Width / 2f, noMonsterSelectedTexture.Height / 2f), 1f, SpriteEffects.None, 0f);
                    }
                    break;
                case SelectedObject.SelectedKind.Substance:
                    Substance selectedSubstance = selectedObject.Selected as Substance;
                    Vector2 min = selectedSubstance.Geom.AABB.Min;
                    Vector2 max = selectedSubstance.Geom.AABB.Max;
                    min.X += Camera.SCREEN_WIDTH / 2f - toEditMap.Camera.Position.X;
                    min.Y += Camera.SCREEN_HEIGHT / 2f - toEditMap.Camera.Position.Y;
                    max.X += Camera.SCREEN_WIDTH / 2f - toEditMap.Camera.Position.X;
                    max.Y += Camera.SCREEN_HEIGHT / 2f - toEditMap.Camera.Position.Y;

                    Vector2 topRight = new Vector2(max.X, min.Y);
                    Vector2 bottomLeft = new Vector2(min.X, max.Y);
                    selectedBrush.Draw(spriteBatch, min, topRight);
                    selectedBrush.Draw(spriteBatch, topRight, max);
                    selectedBrush.Draw(spriteBatch, max, bottomLeft);
                    selectedBrush.Draw(spriteBatch, bottomLeft, min);
                    break;
                default:
                    //do nothing
                    break;
            }

            //draw map boundary
            Vector2 bMin = new Vector2(toEditMap.MapSize.X, toEditMap.MapSize.Y);
            Vector2 bMax = new Vector2(toEditMap.MapSize.X + toEditMap.MapSize.Width, toEditMap.MapSize.Y + toEditMap.MapSize.Height);
            bMin.X -= toEditMap.Camera.Position.X;
            bMin.Y -= toEditMap.Camera.Position.Y;
            bMax.X -= toEditMap.Camera.Position.X;
            bMax.Y -= toEditMap.Camera.Position.Y;
            Vector2 bTopRight = new Vector2(bMax.X, bMin.Y);
            Vector2 bBottomLeft = new Vector2(bMin.X, bMax.Y);
            selectedBrush.Draw(spriteBatch, bMin, bTopRight);
            selectedBrush.Draw(spriteBatch, bTopRight, bMax);
            selectedBrush.Draw(spriteBatch, bMax, bBottomLeft);
            selectedBrush.Draw(spriteBatch, bBottomLeft, bMin);

            //for debugging
#if DEBUG
            spriteBatch.DrawString(Fonts.DebugFont, string.Format("Current Frame: {0}", 1f / gameTime.ElapsedGameTime.Milliseconds * 1000f), new Vector2(0f, 50f), Color.Black);
            spriteBatch.DrawString(Fonts.DebugFont, string.Format("Camera Pos: {0}, {1}", toEditMap.Camera.Position.X, toEditMap.Camera.Position.Y),
                new Vector2(0f, 70f), Color.Black);
            spriteBatch.DrawString(Fonts.DebugFont, mapPropertyForm.SelectedName + " is selected.", new Vector2(0f, 90f), Color.Black);
            MouseState mst = Mouse.GetState();
            spriteBatch.DrawString(Fonts.DebugFont, string.Format("Mouse PosL {0}, {1}", mst.X, mst.Y), new Vector2(0f, 110f), Color.Black);
#endif
            spriteBatch.End();
        }

        #endregion

        #region Events

        private void addEventHandlers()
        {
            mainForm.Move += new EventHandler(mainForm_Move);
            mainForm.Resize += new EventHandler(mainForm_Resize);
            mainForm.Activated += new EventHandler(mainForm_Activated);
            mainForm.MouseDown += new MouseEventHandler(mainForm_MouseDown);
            mainForm.MouseUp += new MouseEventHandler(mainForm_MouseUp);
            mainForm.MouseMove += new MouseEventHandler(mainForm_MouseMove);

            mapPropertyForm.Move += new EventHandler(mapPropertyForm_Move);

            vScrollBar.ValueChanged += new EventHandler(vScrollBar_ValueChanged);
            vScrollBar.KeyUp += new KeyEventHandler(vScrollBar_KeyUp);
            vScrollBar.MouseLeave += new EventHandler(vScrollBar_MouseLeave);

            hScrollBar.MouseLeave += new EventHandler(hScrollBar_MouseLeave);
            hScrollBar.KeyUp += new KeyEventHandler(hScrollBar_KeyUp);
            hScrollBar.ValueChanged += new EventHandler(hScrollBar_ValueChanged);

            newToolStripMenuItem.Click += new EventHandler(newToolStripMenuItem_Click);
            saveToolStripMenuItem.Click += new EventHandler(saveToolStripMenuItem_Click);
            saveAsToolStripMenuItem.Click += new EventHandler(saveAsToolStripMenuItem_Click);
            loadToolStripMenuItem.Click += new EventHandler(loadToolStripMenuItem_Click);
            backToTheGameToolStripMenuItem.Click += new EventHandler(backToTheGameToolStripMenuItem_Click);
            mapInfoStripMenuItem.Click += new EventHandler(mapInfoStripMenuItem_Click);
        }

        private void removeEventHandlers()
        {
            mainForm.Move -= mainForm_Move;
            mainForm.Resize -= mainForm_Resize;
            mainForm.Activated -= mainForm_Activated;
            mainForm.MouseDown -= mainForm_MouseDown;
            mainForm.MouseUp -= mainForm_MouseUp;
            mainForm.MouseMove -= mainForm_MouseMove;

            mapPropertyForm.Move -= mapPropertyForm_Move;

            vScrollBar.ValueChanged -= vScrollBar_ValueChanged;
            vScrollBar.KeyUp -= vScrollBar_KeyUp;
            vScrollBar.MouseLeave -= vScrollBar_MouseLeave;

            hScrollBar.MouseLeave -= hScrollBar_MouseLeave;
            hScrollBar.KeyUp -= hScrollBar_KeyUp;
            hScrollBar.ValueChanged -= hScrollBar_ValueChanged;

            newToolStripMenuItem.Click -= newToolStripMenuItem_Click;
            saveToolStripMenuItem.Click -= saveToolStripMenuItem_Click;
            saveAsToolStripMenuItem.Click -= saveAsToolStripMenuItem_Click;
            loadToolStripMenuItem.Click -= loadToolStripMenuItem_Click;
            backToTheGameToolStripMenuItem.Click -= backToTheGameToolStripMenuItem_Click;
            mapInfoStripMenuItem.Click -= mapInfoStripMenuItem_Click;
        }

        void mainForm_Activated(object sender, EventArgs e)
        {
            Win32.SetWindowPos((int)mapPropertyForm.Handle, Win32.HWND_TOP, mapPropertyForm.Location.X, mapPropertyForm.Location.Y, mapPropertyForm.Size.Width, mapPropertyForm.Size.Height, Win32.SWP_NOACTIVATE);
        }

        void mainForm_Resize(object sender, EventArgs e)
        {
            mapPropertyForm.WindowState = mainForm.WindowState;
        }

        void mapPropertyForm_Move(object sender, EventArgs e)
        {
            mainForm_Move(sender, e);
        }

        void mainForm_Move(object sender, EventArgs e)
        {
            mapPropertyForm.Location =
                new System.Drawing.Point(mainForm.Location.X + mainForm.Size.Width, mainForm.Location.Y);
        }

        void mainForm_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && lastButton == MouseButtons.Left)
            {
                mapPropertyForm.RefreshGrid();
            }
            isDragging = false;
            lastButton = MouseButtons.None;
        }

        void mainForm_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDragging)
            {
                if (e.Button == MouseButtons.Right && lastButton == MouseButtons.Right)
                {
                    Point offset = new Point(lastScrollPoint.X + lastDragPoint.X - e.X, lastScrollPoint.Y + lastDragPoint.Y - e.Y);
                    if (offset.X > hScrollBar.Maximum - ScrollOffset)
                        hScrollBar.Maximum = offset.X + ScrollOffset;
                    if (offset.X < hScrollBar.Minimum + ScrollOffset)
                        hScrollBar.Minimum = offset.X - ScrollOffset;
                    if (offset.Y > vScrollBar.Maximum - ScrollOffset)
                        vScrollBar.Maximum = offset.Y + ScrollOffset;
                    if (offset.Y < vScrollBar.Minimum + ScrollOffset)
                        vScrollBar.Minimum = offset.Y - ScrollOffset;

                    hScrollBar.Value = offset.X;
                    vScrollBar.Value = offset.Y;
                }
                if (e.Button == MouseButtons.Left && lastButton == MouseButtons.Left)
                {
                    if (selectedObject.Kind == SelectedObject.SelectedKind.Substance)
                    {
                        Substance selectedSubstance = selectedObject.Selected as Substance;
                        Substance.DataSet ds = dataTable[selectedSubstance];
                        if (!ds.IsLocked)
                        {
                            Vector2 newPos = new Vector2(e.X - lastDragPoint.X + lastScrollPoint.X, e.Y - lastDragPoint.Y + lastScrollPoint.Y);
                            selectedSubstance.Position = newPos;
                            ds.Position = newPos;
                            toEditMap.IsSaved = false;
                        }
                    }
                    else if (selectedObject.Kind == SelectedObject.SelectedKind.PosDesc)
                    {
                        PosDesc selectedPosDesc = selectedObject.Selected as PosDesc;
                        if (!selectedPosDesc.IsLocked)
                        {
                            selectedPosDesc.Position = new Vector2(e.X - lastDragPoint.X + lastScrollPoint.X, e.Y - lastDragPoint.Y + lastScrollPoint.Y);
                            toEditMap.IsSaved = false;
                        }
                    }
                }
            }
        }

        void mainForm_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                lastScrollPoint.X = hScrollBar.Value;
                lastScrollPoint.Y = vScrollBar.Value;
            }

            if (e.Button == MouseButtons.Left)
            {
                selectedObject.Selected = null;

                Vector2 pos = new Vector2(toEditMap.Camera.Position.X + e.X - Camera.SCREEN_WIDTH / 2f,
                    toEditMap.Camera.Position.Y + e.Y - Camera.SCREEN_HEIGHT / 2f);

                //StartCharPosDesc를 가리키나
                if (toEditMap.StartPos.X - startPosTexture.Width / 2f <= pos.X && pos.X <= toEditMap.StartPos.X + startPosTexture.Width / 2f &&
                    toEditMap.StartPos.Y - startPosTexture.Height / 2f <= pos.Y && pos.Y <= toEditMap.StartPos.Y + startPosTexture.Height / 2f)
                {
                    selectedObject.Selected = startCharPosDesc;
                    mapPropertyForm.Select(startCharPosDesc);
                    lastScrollPoint.X = (int)startCharPosDesc.Position.X;
                    lastScrollPoint.Y = (int)startCharPosDesc.Position.Y;
                }
                else
                {
                    //check whether cursor is on a substance or not.
                    //object peeking..... changed by Jihyun, Yu, ticket #19
                    foreach (var s in toEditMap.Substances.Values)
                        if (s.Geom.Collide(pos))
                            if (selectedObject.Selected == null || (selectedObject.Selected as Substance).Layer <= s.Layer)
                            {
                                selectedObject.Selected = s;
                            }

                    //check whether cursor is on a monster block or not.
                    for (int i = monsterBlockDescs.Count - 1; i >= 0; --i)
                    {
                        Vector2 v = monsterBlockDescs[i].Position;
                        if (v.X - noMontserTexture.Width / 2f <= pos.X && pos.X <= v.X + noMontserTexture.Width / 2f &&
                            v.Y - noMontserTexture.Height / 2f <= pos.Y && pos.Y <= v.Y + noMontserTexture.Height / 2f)
                        {
                            selectedObject.Selected = monsterBlockDescs[i];
                            break;
                        }
                    }

                    if (selectedObject.Kind == SelectedObject.SelectedKind.Substance)
                    {
                        Substance selectedSubstance = selectedObject.Selected as Substance;
                        mapPropertyForm.Select(dataTable[selectedSubstance]);
                        lastScrollPoint.X = (int)selectedSubstance.Position.X;
                        lastScrollPoint.Y = (int)selectedSubstance.Position.Y;
                    }
                    else if (selectedObject.Kind == SelectedObject.SelectedKind.PosDesc)
                    {
                        mapPropertyForm.Select(selectedObject.Selected);
                        lastScrollPoint.X = (int)(selectedObject.Selected as PosDesc).Position.X;
                        lastScrollPoint.Y = (int)(selectedObject.Selected as PosDesc).Position.Y;
                    }
                }
            }

            lastDragPoint.X = e.X;
            lastDragPoint.Y = e.Y;
            lastButton = e.Button;
            isDragging = true;
        }

        void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //현재 작성중인 저장되지 않은 맵이 있는가 본다.
            //저장안되었으면 저장할것인가 묻고 저장한다.
            //그리고 바로 새로 맵 만들면 될 듯.
            if (toEditMap != null && !toEditMap.IsSaved)
            {
                bool saveFlag = true;
                while (saveFlag)
                {
                    DialogResult result = MessageBox.Show("현재 맵이 저장되지 않았습니다. 저장하시겠습니까?", "Folder Map Editor", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning);
                    switch (result)
                    {
                        case DialogResult.Yes:
                            if (!mapFileName.Equals(string.Empty))
                            {
                                saveMap();
                                saveFlag = false;
                            }
                            else
                                saveFlag = !saveMapDialog();
                            break;
                        case DialogResult.No:
                            saveFlag = false;
                            break;
                        case DialogResult.Cancel:
                            return;
                    }
                }
            }
            string mapName = string.Empty;
            DialogResult buttonResult = DialogResult.Cancel;
            while (buttonResult == DialogResult.Cancel)
            {
                buttonResult = mapNameDialog.ShowDialog();
                mapName = mapNameDialog.TextResult;
                if (mapName.Equals(string.Empty))
                    buttonResult = DialogResult.Cancel;
            }
            Map map = new Map();
            map.IsMapEditing = true;
            map.Name = mapName;
            setFormTitle(mapName);
            toEditMap = map;
            resetMapEditor();
        }

        void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            /*if (toEditMap.IsSaved) //또 저장할 필요 없을 때는 저장하지 않는다.
                return;*/
            //퍼포먼스가 떨어지더라도 확실하게 저장하기 위해서 지움.

            //만약 지금까지 세이브 한 적이 없어서 저장할 파일 이름을 알 수 없을 때는 새로 dialog를 연다.
            if (mapFileName.Equals(string.Empty))
                saveMapDialog();
            else
                saveMap();
        }

        void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //무조건 새로 dialog를 연다.
            saveMapDialog();
        }

        void loadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //현재 작성중인 저장되지 않은 맵이 있는가 본다.
            //저장안되었으면 저장할것인가 묻고 저장한다.
            //그리고 바로 새로 맵 만들면 될 듯.
            if (toEditMap != null && !toEditMap.IsSaved)
            {
                bool saveFlag = true;
                while (saveFlag)
                {
                    DialogResult result = MessageBox.Show("현재 맵이 저장되지 않았습니다. 저장하시겠습니까?", "Folder Map Editor", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning);
                    switch (result)
                    {
                        case DialogResult.Yes:
                            if (!mapFileName.Equals(string.Empty))
                            {
                                saveMap();
                                saveFlag = false;
                            }
                            else
                                saveFlag = !saveMapDialog();
                            break;
                        case DialogResult.No:
                            saveFlag = false;
                            break;
                        case DialogResult.Cancel:
                            return;
                    }
                }
            }

            OpenFileDialog openDialog = new OpenFileDialog();
            openDialog.Filter = "xml files (*.xml)|*.xml|All files(*.*)|*.*";
            openDialog.FilterIndex = 0;
            openDialog.RestoreDirectory = true;
            openDialog.Multiselect = false;

            if (openDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    XmlReaderSettings xmlSettings = new XmlReaderSettings();
                    using (XmlReader xmlReader = XmlReader.Create(openDialog.FileName, xmlSettings))
                    {
                        toEditMap = IntermediateSerializer.Deserialize<Map>(xmlReader, openDialog.FileName);
                        toEditMap.LoadContent(content);
                    }
                    ResourceManager.Instance.BindDatas(toEditMap);
                    mapFileName = openDialog.FileName;
                    toEditMap.IsMapEditing = true;
                    setFormTitle(toEditMap.Name);
                    resetMapEditor();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        void backToTheGameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MapEditorClosed(this, new MapEditorCloseEventArgs(CloseMapEditor()));
        }

        void mapInfoStripMenuItem_Click(object sender, EventArgs e)
        {
            mapInfoDialog.SetData(toEditMap);
            isMapInfoDialoging = true;
            mapInfoDialog.ShowDialog();
            isMapInfoDialoging = false;
            setFormTitle(toEditMap.Name);
            toEditMap.IsSaved = false;
            startCharPosDesc.Position = toEditMap.StartPos;
        }

        void vScrollBar_ValueChanged(object sender, EventArgs e)
        {
            toEditMap.Camera.Position = new Vector2(hScrollBar.Value, vScrollBar.Value);
        }

        void vScrollBar_MouseLeave(object sender, EventArgs e)
        {
            if (vScrollBar.Value > vScrollBar.Maximum - ScrollOffset)
                vScrollBar.Maximum = vScrollBar.Value + ScrollOffset;

            if (vScrollBar.Value < vScrollBar.Minimum + ScrollOffset)
                vScrollBar.Minimum = vScrollBar.Minimum - ScrollOffset;
        }

        void vScrollBar_KeyUp(object sender, KeyEventArgs e)
        {
            if (vScrollBar.Value > vScrollBar.Maximum - ScrollOffset)
                vScrollBar.Maximum = vScrollBar.Value + ScrollOffset;

            if (vScrollBar.Value < vScrollBar.Minimum + ScrollOffset)
                vScrollBar.Minimum = vScrollBar.Minimum - ScrollOffset;
        }

        void hScrollBar_MouseLeave(object sender, EventArgs e)
        {
            if (hScrollBar.Value > hScrollBar.Maximum - ScrollOffset)
                hScrollBar.Maximum = hScrollBar.Value + ScrollOffset;

            if (hScrollBar.Value < hScrollBar.Minimum + ScrollOffset)
                hScrollBar.Minimum = hScrollBar.Minimum - ScrollOffset;
        }

        void hScrollBar_ValueChanged(object sender, EventArgs e)
        {
            toEditMap.Camera.Position = new Vector2(hScrollBar.Value, vScrollBar.Value);
        }

        void hScrollBar_KeyUp(object sender, KeyEventArgs e)
        {
            if (hScrollBar.Value > hScrollBar.Maximum - ScrollOffset)
                hScrollBar.Maximum = hScrollBar.Value + ScrollOffset;

            if (hScrollBar.Value < hScrollBar.Minimum + ScrollOffset)
                hScrollBar.Minimum = hScrollBar.Minimum - ScrollOffset;
        }

        void startCharPosDesc_PositionChanged(object sender, PosDescEventArgs e)
        {
            toEditMap.StartPos = e.NewPos;
        }

        void pd_PositionChanged(object sender, PosDescEventArgs e)
        {
            Debug.Assert(toEditMap.MonsterBlockPositions.IndexOf(e.OldPos) >= 0);
            toEditMap.MonsterBlockPositions.Remove(e.OldPos);
            toEditMap.MonsterBlockPositions.Add(e.NewPos);
        }

        #endregion

        #region Entry and Closing Point
        public MapEditor()
        {
        }
        /// <summary>
        /// 맵 에디팅을 시작. map은 null이어도 됨.
        /// </summary>
        /// <param name="map"></param>
        public void StartMapEditor(Map map)
        {
            if (map.IsFolded)
            {
                return;
            }

            //visibility
            screenManager.Game.IsMouseVisible = true;
            vScrollBar.Visible = true;
            hScrollBar.Visible = true;
            menuStrip1.Visible = true;

            isMapEditing = true;
            toEditMap = map;

            graphics.IsFullScreen = false;
            oldTitle = mainForm.Text;
            
            if (!mapPropertyForm.HasListView)
                mapPropertyForm.SetListView();
            mapPropertyForm.Show();
            mainForm_Move(null, null);
            mainForm.Activate();

            if (toEditMap == null)
            {
                newToolStripMenuItem_Click(null, null);
            }
            else
            {
                resetMapEditor();
                oldCameraPos = map.Camera.Position;
            }
            toEditMap.IsSaved = false;

            setFormTitle(toEditMap.Name);

            addEventHandlers();
        }

        public Map CloseMapEditor()
        {
            mapPropertyForm.Hide();
            if (mapInfoDialog.CanFocus)
                mapInfoDialog.Close();

            isMapEditing = false;
            toEditMap.IsMapEditing = false;
            mainForm.Text = oldTitle;
            screenManager.Game.IsMouseVisible = false;
            vScrollBar.Visible = false;
            hScrollBar.Visible = false;
            menuStrip1.Visible = false;
            
            if (oldCameraPos.HasValue)
                toEditMap.Camera.Position = oldCameraPos.Value;

            removeEventHandlers();
            //TODO :: MapProperty form이 가지고 있는 Image List 비우기?

            //Map이 가진 각종 스테이트를 초기화 한다. (아마 추후에 MapStatus관련해서 뭔가 해야될 것이 있을 듯)
            ResourceManager.Instance.UnbindDatas(toEditMap);
            ResourceManager.Instance.BindDatas(toEditMap);   //수정 09. 08. 17. 02:31 by chorice. 기존에는 BindPlayer()만 했으나 MonsterBlock을 추가하면서 BindDatas()로 바꿈.
            //왜냐하면 MonsterBlock은 Vector2 값만 갖고 있기 때문에 꼭 BindDatas()를 통해 Substance로 만들어 주어야 하니까.

            return toEditMap;
        }
        #endregion
    }
}
#endif